# Copyright 2012 Robert Muth
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 3
# of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

"""
HocusPocus Plugin "tasks"
"""

# python imports
import logging
import subprocess
import threading
import tornado.web
import tornado.websocket

# local imports
import utils
import vlc_driver

# ======================================================================

tornado.options.define(
    "task_commands",
    default="",
    type=str,
    multiple=True,
    help="TODO")

OPTIONS = tornado.options.options

# ======================================================================
def GetCommand(name):
    for s in OPTIONS.task_commands:
        tokens = s.split(":")
        if name == tokens[0]:
            return tokens[1].split()

    logging.error("unknown command %s", name)
    return None

def GetCommands():
    names = []
    for s in OPTIONS.task_commands:
        tokens = s.split(":")
        names.append(tokens[0])
    return names



RUNNING_TASK = None

LISTENERS = []

class Task:
    """ class for abstracting a process
    """
    def __init__(self, name, cmd, listeners, history_limit):
        logging.info("initiating task: %s)", str(cmd))
        self._process = subprocess.Popen(cmd,
                                         close_fds=True,
                                         stdin=subprocess.PIPE,
                                         stderr=subprocess.STDOUT,
                                         stdout=subprocess.PIPE)
        self._name = name
        self._output = []
        self._limit = history_limit
        self._listeners = listeners
        self._status = "running"
        self._thread = threading.Thread(target=self.Communicate)
        self._thread.start()

    def Communicate(self):
        """reads a character at a time -  blocking"""
        process = self._process
        while self._status != "terminated":
            line = process.stdout.read(1)
            if not line:
                process.wait()
                result = str(process.returncode)
                line = "Process has terminated with result " + result
                self._status = "terminated"
            if (self._output and
                not self._output[-1].endswith("\n") and
                len(self._output[-1]) < 80):
                self._output[-1] += line
            else:
                self._output.append(line)
            if len(self._output) > self._limit:
                self._output.pop(0)

            for l in self._listeners:
                l.write_message(line)

    def GetHistory(self):
        return  self._output[:]

    def Kill(self):
        self._process.terminate()
        for l in self._listeners:
            l.write_message("killing task\n")
        self._status = "terminated"

    def Name(self):
        return self._name

    def Status(self):
        return self._status



class Handler(tornado.web.RequestHandler):
    """Displays a the task page

    currently only one task can be active
    """

    def initialize(self, template_args):
        logging.debug("task hander init")
        self._template_args = template_args

    @tornado.web.asynchronous
    def get(self, dummy_p, *dummy_k):
        logging.info("task handler request")
        global RUNNING_TASK
        # print(RUNNING_TASK)
        if RUNNING_TASK is None:
            status = "No task is running"
        else:
            status = "task %s status: %s" % (RUNNING_TASK.Name(),
                                        RUNNING_TASK.Status())

        self._template_args["status"] = status
        self._template_args["commands"] = GetCommands() + ["kill"]
        self.write(self.render_string("task.html", **self._template_args))
        self.finish()


class CommandHandler(tornado.web.RequestHandler):
    """Handle AJAXy requests
    """

    def initialize(self, template_args):
        logging.debug("task command handler init")
        self._template_args = template_args

    @tornado.web.asynchronous
    def get(self, dummy_p, *dummy_k):
        global RUNNING_TASK, LISTENERS
        command = self.get_argument("command")
        logging.info("task command handler request [%s]", command)
        if command == "kill":
            if not RUNNING_TASK is None:
                RUNNING_TASK.Kill()
                RUNNING_TASK = None
                self.write("task killed")
        elif RUNNING_TASK is None or RUNNING_TASK.Status() == "terminated":
            RUNNING_TASK = Task(command, GetCommand(command), LISTENERS, 50)
            self.write("task %s started" % command)
        else:
            self.write("another task is running")
        self.finish()



class WebSocketHandler(tornado.websocket.WebSocketHandler):
    """websocket handler for streaming task stdout to browser
    """

    def open(self, _):
        global RUNNING_TASK, LISTENERS
        LISTENERS.append(self)
        if not RUNNING_TASK is None:
            for line in RUNNING_TASK.GetHistory():
                self.write_message(line)
        #self.receive_message(self.on_message)

    def on_message(self, message):
        pass

    def on_close(self):
        LISTENERS.remove(self)

def GetHandlers():
    return [(r"/task/(.*)", Handler),
            (r"/task_command(.*)", CommandHandler),
            (r"/task_websocket(.*)", WebSocketHandler),
            ]

def GetDependencies():
    return []

